package cn.seaboot.admin.security.token;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

/**
 * 身份令牌对象实体
 * <p>
 * Token 与 Provider 是对应存在的，最好避免采用继承的方式写 Token。
 *
 * @author Mr.css
 * @version 2021-12-23 10:51
 * @see UsernamePasswordAuthenticationToken
 */
public class UserToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 5072430419870679687L;

    /**
     * 对象主体，通常指账号
     */
    private final String principal;
    /**
     * 证书，通常指密码
     */
    private String credentials;

    //  ~ Constructors
    //  ===================================================================================================

    /**
     * 使用此函数，构造一个未认证的令牌
     * <p>
     * This constructor can be safely used by any code that wishes to create a
     * <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()}
     * will return <code>false</code>.
     *
     * @param principal   对象主体，通常指账号
     * @param credentials 证书，通常指密码
     */
    public UserToken(String principal, String credentials) {
        super(null);
        this.principal = principal;
        this.credentials = credentials;
        setAuthenticated(false);
    }

    /**
     * 使用此函数，构造一个经过认证的身份令牌
     * <p>
     * This constructor should only be used by <code>AuthenticationManager</code> or
     * <code>AuthenticationProvider</code> implementations that are satisfied with
     * producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
     * authentication token.
     *
     * @param principal   对象主体，通常指账号
     * @param credentials 证书，通常指密码
     * @param authorities 权限列表
     */
    public UserToken(String principal, String credentials,
                     Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true); //  must use super, as we override
    }

    //  ~ Methods
    //  ========================================================================================================

    public String getCredentials() {
        return this.credentials;
    }

    public String getPrincipal() {
        return this.principal;
    }

    /**
     * 认证标志位，这个函数不能被调用，只能通过构造函数进行认证
     *
     * @param isAuthenticated 是否经过认证
     * @throws IllegalArgumentException 未经过认证
     */
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException(
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }
        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        credentials = null;
    }
}
